﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="StockServiceTests.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the StockServiceTests type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ServiceTests
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using DocProcessingRepository.Interfaces;
  using Entities;
  using Exceptions;
  using FluentAssertions;
  using Moq;
  using NUnit.Framework;
  using ServiceInterfaces;
  using Services;

  [Category("Unit")]
  [TestFixture]
  public class StockServiceTests
  {
    private Mock<IStockRepository> stockRepositoryMock;
    private IStockService stockService;

    [SetUp]
    public void Setup()
    {
      this.stockRepositoryMock = new Mock<IStockRepository>();
      this.stockService = new StockService(this.stockRepositoryMock.Object);
    }

    [Test]
    public void GivenAStockType_WhenITryToGetTheStock_TheStockShouldBeReturned()
    {
      var stock = new List<StockEntity>();

      this.stockRepositoryMock.Setup(
        x => x.GetStockByType(It.IsAny<String>(), It.IsAny<String>()))
        .Returns(stock);

      List<StockEntity> returnedStock = this.stockService.GetStockByType("stock", "filter");

      this.stockRepositoryMock.Verify(x => x.GetStockByType(It.IsAny<String>(), It.IsAny<String>()), Times.Once);

      ((Object)returnedStock).Should().BeSameAs(stock);
    }

    [Test]
    public void GivenAStockType_WhenITryToGetTheStock_AndDatabaseIsUnavailable_ThenADocProcessingExceptionIsReturned()
    {
      this.stockRepositoryMock.Setup(
        x => x.GetStockByType(It.IsAny<String>(), It.IsAny<String>()))
        .Throws<DocProcessingException>();

      Action act = () => this.stockService.GetStockByType("stock", "filter");

      act.ShouldThrow<DocProcessingException>();
    }

    [Test]
    public void GivenValidData_WhenITryToCreateANewStock_TheNewStockItemIsCreatedAndReturned()
    {
      var stock = new StockEntity();

      var existingStock = new List<StockEntity> { new StockEntity { Code = "code1" } };

      this.stockRepositoryMock.Setup(
        x => x.GetStockByType(It.IsAny<String>(), It.IsAny<String>()))
        .Returns(existingStock);

      this.stockRepositoryMock.Setup(
        x =>
        x.CreateStock(
          It.IsAny<Int32>(),
          It.IsAny<String>(),
          It.IsAny<String>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Char>(),
          It.IsAny<String>()))
        .Returns(stock);

      StockEntity createdStock = this.stockService.CreateStock(1, "code2", "description", 2, 3, 4, '0', "White");

      this.stockRepositoryMock.Verify(
        x => x.CreateStock(
          It.IsAny<Int32>(),
          It.IsAny<String>(),
          It.IsAny<String>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
        It.IsAny<Char>(),
        It.IsAny<String>()),
        Times.Once);

      createdStock.Should().BeSameAs(stock);
    }

    [Test]
    public void GivenValidData_WhenITryToCreateANewStock_AndADuplicateIsFound_ThenADocProcessingExceptionIsReturned()
    {
      var stock = new StockEntity();

      var existingStock = new List<StockEntity>
                            {
                              new StockEntity
                                {
                                  Code = "code",
                                  Description = "description",
                                  Weight = 2,
                                  SizeX = 3,
                                  SizeY = 4,
                                  Facing = "0",
                                  Colour = "White"
                                }
                            };

      this.stockRepositoryMock.Setup(
        x => x.GetStockByType(It.IsAny<String>(), It.IsAny<String>()))
        .Returns(existingStock);

      this.stockRepositoryMock.Setup(
        x =>
        x.CreateStock(
          It.IsAny<Int32>(),
          It.IsAny<String>(),
          It.IsAny<String>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Char>(),
          It.IsAny<String>()))
        .Returns(stock);

      try
      {
        this.stockService.CreateStock(1, "code", "description", 2, 3, 4, '0', "White");
      }
      catch (DocProcessingException ex)
      {
        ex.Message.Should().Be("Duplicate stock item found");
        return;
      }

      Assert.Fail("A DocProcessingException exception should have been raised");
    }

    [Test]
    public void GivenValidData_WhenITryToCreateANewStock_AndDatabaseIsUnavailable_ThenADocProcessingExceptionIsReturned()
    {
      this.stockRepositoryMock.Setup(
        x =>
        x.CreateStock(
          It.IsAny<Int32>(),
          It.IsAny<String>(),
          It.IsAny<String>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Int32>(),
          It.IsAny<Char>(),
          It.IsAny<String>()))
        .Throws<DocProcessingException>();

      Action act = () => this.stockService.CreateStock(1, "code", "description", 2, 3, 4, '0', "White");

      act.ShouldThrow<DocProcessingException>();
    }
  }
}
